package com.fsnbigdata.web;

import com.fsnbigdata.domain.security.Authority;
import com.fsnbigdata.domain.security.User;
import com.fsnbigdata.service.api.StatisticService;
import com.fsnbigdata.service.api.UserService;
import com.fsnbigdata.service.impl.CustomUserDetailsService;
import com.fsnbigdata.util.Base64;
import com.fsnbigdata.util.CheckPasswdByRegex;
import com.fsnbigdata.vo.UserVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.*;

import java.security.Principal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static org.springframework.web.bind.annotation.RequestMethod.*;

/**
 * Created by fan.jin on 2016-10-15.
 */

@RestController
@RequestMapping( value = "/api/user", produces = MediaType.APPLICATION_JSON_VALUE )
@Api(tags = "User", description = "用户信息" )
public class UserController {

    @Autowired
    private UserService userService;

    @Autowired
    private CustomUserDetailsService userDetailsService;

    @Autowired
    private StatisticService statisticService;

    @GetMapping( value = "/{username}" )
    @PreAuthorize("hasRole('USER_ADMIN')")
    public User loadByUsername(@PathVariable String username ) {
        return this.userService.findByUsername(username);
    }

    @PutMapping( value = "/{username}" )
    @PreAuthorize("hasRole('USER_ADMIN')")
    public User updateByUsername(@PathVariable String username , @RequestBody User user) {
        //base64解密
        try {
            username = new String(Base64.decryptBASE64(username));
            user.setUsername(new String(Base64.decryptBASE64(user.getUsername())));
        }catch (Exception e){
            System.out.println("转换失败！");
        }
        User origin = userService.findByUsername(username);
        user.copyPassword(origin.getPassword());
        user.setEmail(origin.getEmail());

        return userService.save(user);
    }

    @PutMapping( value = "/{username}/change-password" )
    @PreAuthorize("hasRole('USER_ADMIN')")
    public ResponseEntity<?> changePasswordByUsername(@PathVariable String username , @RequestParam("password") String password) {
        //base64解密
//        try {
//            username = (new String(Base64.decryptBASE64(username)));
//            password = (new String(Base64.decryptBASE64(password)));
//        }catch (Exception e){
//            System.out.println("转换失败！");
//        }
        Map<String, String> result = new HashMap<>();
        if (CheckPasswdByRegex.checkPassword(password).equals("1")){
            userDetailsService.changePasswordByUsername(username, password);
            result.put( "result", "success" );
            return ResponseEntity.accepted().body(result);
        }
        result.put("result","密码需同时包含数字、字母和英文字符");
        return ResponseEntity.badRequest().body(result);
    }

    @RequestMapping( method = GET, value= "/all")
    @PreAuthorize("hasRole('USER_ADMIN')")
    public List<User> loadAll(Principal principal) {
        User userAdmin = this.userService.findByUsername(principal.getName());
        List<User> ret = null;
        if(userAdmin.getUsername().equals("admin")){
            ret = this.userService.findAll();
        }else{
            List dbRoles = userAdmin.getAuthorities().stream().map(it-> it.getAuthority()).filter(it -> it.startsWith("ROLE_DB")).collect(Collectors.toList());
            ret = this.userService.findAll();
            ret = ret.stream().
                    filter(it ->
                    {List ver = it.getAuthorities().stream().map(au -> au.getAuthority()).collect(Collectors.toList());
                        return ver.containsAll(dbRoles) ? true : false;
                    }).
                    filter(it -> {if(it.getUsername().equals("admin")){ return false;}else{return true;}})
                    .collect(Collectors.toList());
        }

        return ret.stream().map(
            user -> {
                UserVo userVo = new UserVo();
                userVo.setId(user.getId());
                userVo.setName(user.getName());
                userVo.setUsername(user.getUsername());
                userVo.setAuthorities((List<Authority>)user.getAuthorities());
                userVo.setEnabled(user.isEnabled());
                userVo.setLastPasswordResetDate(user.getLastPasswordResetDate());
                userVo.setStatistic(statisticService.countByCreator(user.getUsername()));
                return userVo;
            }
        ).collect(Collectors.toList());
    }

    @PostMapping(value = "/onboard")
    @PreAuthorize("hasRole('USER_ADMIN')")
    //@ApiOperation(value = "Create New User")
    public User create(Principal principal, @RequestBody User user, @RequestParam("password") String password){
        //base64解密
        try {
            password = (new String(Base64.decryptBASE64(password)));
            user.setUsername(new String(Base64.decryptBASE64(user.getUsername())));
        }catch (Exception e){
            System.out.println("转换失败！");
        }
        if (!CheckPasswdByRegex.checkPassword(password).equals("1")){
            User user2 = new User();
            user2.setCode("passwordSimple");
            return user2;
        }
        if (this.userService.findByUsername(user.getUsername()) != null){
            User user1 = new User();
            user1.setCode("existUsername");
            return user1;
        }
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        user.setPassword(passwordEncoder.encode(password));

        List authorities = new ArrayList<Authority>();
        authorities.add(new Authority("ROLE_USER"));
        user.setAuthorities(authorities);

        User userAdmin = this.userService.findByUsername(principal.getName());

        userAdmin.getAuthorities().stream().forEach(
                it-> {
                    Authority authority = ((Authority)it);
                    if (authority.getName().startsWith("ROLE_DB")) {
                        authorities.add(new Authority(authority.getName()));
                    }
                }
        );

        user.getAuthorities().stream().forEach(it-> ((Authority)it).setUser(user));

        return this.userService.save(user);
    }

    /*
     *  We are not using userService.findByUsername here(we could),
     *  so it is good that we are making sure that the user has role "ROLE_USER"
     *  to access this endpoint.
     */
    @RequestMapping( method = GET, value = "/whoami")
    @PreAuthorize("hasRole('USER')")
    public User user(Principal user) {
        return this.userService.findByUsername(user.getName());
    }


    @PutMapping(value = "/profile")
    @PreAuthorize("hasRole('USER')")
    @ApiOperation(value = "Update User Profile")
    public User update(Principal principal, @RequestBody User user) {
        if(!principal.getName().equals(user.getUsername())){
            //TODO 不允许修改username
            return null;
        }

        User origin = userService.findByUsername(principal.getName());
        user.copyPassword(origin.getPassword());

        user.getAuthorities().stream().forEach(it-> ((Authority)it).setUser(user));

        return userService.save(user);
    }


    @RequestMapping(value = "/change-password", method = RequestMethod.POST)
    @PreAuthorize("hasRole('USER')")
    public ResponseEntity<?> changePassword(@RequestBody PasswordChanger passwordChanger) {
        //base64解密
        try {
            passwordChanger.oldPassword = (new String(Base64.decryptBASE64(passwordChanger.oldPassword)));
            passwordChanger.newPassword = (new String(Base64.decryptBASE64(passwordChanger.newPassword)));
        }catch (Exception e){
            System.out.println("转换失败！");
        }
        Map<String, String> result = new HashMap<>();
        if (CheckPasswdByRegex.checkPassword(passwordChanger.newPassword).equals("1")){
            userDetailsService.changePassword(passwordChanger.oldPassword, passwordChanger.newPassword);
            result.put( "result", "success" );
            return ResponseEntity.accepted().body(result);
        }
        result.put("result","密码需同时包含数字、字母和英文字符");
        return ResponseEntity.badRequest().body(result);
    }

    static class PasswordChanger {
        public String oldPassword;
        public String newPassword;
    }

//    @RequestMapping(method = PUT, value = "/user/{userId}")
//    @PreAuthorize("hasRole('USER_ADMIN')")
//    public User update(@RequestBody User user){
//        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
//        user.setPassword(passwordEncoder.encode("123"));
//        Authority authority = new Authority();
//        authority.setName("ROLE_USER");
//        List authorities = new ArrayList<Authority>();
//
//        authorities.add(authority);
//
//        user.setAuthorities(authorities);
//
//        return this.userService.save(user);
//    }

    @GetMapping("getImage")
    public Long getAllByImage(){
        return userService.getAllImage();

    }
}
